gbfile: Add wrappers for each specific file api (standard, gzlib, AND memory).
authoroliskoli <oliskoli>
Thu, 11 Sep 2008 20:40:33 +0000 (20:40 +0000)
committeroliskoli <oliskoli>
Thu, 11 Sep 2008 20:40:33 +0000 (20:40 +0000)
A 'memory only' gbfile can be created with 'gbfopen(NULL, "w", MYNAME)'.

gbfile.c
gbfile.h

index bf450791b076d4b17258128542210bcf661319a8..bec1cf55ce579cb788841b68bdc8dd7e1de8a80e 100644 (file)
--- a/gbfile.c
+++ b/gbfile.c
@@ -1,7 +1,8 @@
 /*
 
     Common GPSBabel file I/O API
-    Copyright (C) 2006 Olaf Klein, o.b.klein@gpsbabel.org
+
+    Copyright (C) 2006,2007,2008 Olaf Klein, o.b.klein@gpsbabel.org
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
  *
  */
 
+
+/*******************************************************************************/
+/* %%%                          file api wrappers                           %%% */
+/*******************************************************************************/
+
+#if !ZLIB_INHIBITED
+
+/*******************************************************************************/
+/* %%%                            Zlib file api                            %%% */
+/*******************************************************************************/
+
+static gbfile *
+gzapi_open(gbfile *self, const char *mode)
+{
+       char openmode[32];
+
+       self->gzapi = 1;
+
+       /* under non-posix systems files MUST be opened in binary mode */
+
+       strcpy(openmode, mode);
+       if (strchr(mode, 'b') == NULL)
+               strncat(openmode, "b", sizeof(openmode));
+
+       if (self->is_pipe) {
+               FILE *fd;
+               if (self->mode == 'r')
+                       fd = stdin;
+               else
+                       fd = stdout;
+               SET_BINARY_MODE(fd);
+               self->handle.gz = gzdopen(fileno(fd), openmode);
+       }
+       else
+               self->handle.gz = gzopen(self->name, openmode);
+
+       if (self->handle.gz == NULL) {
+               fatal("%s: Cannot %s file '%s'!\n", 
+                       self->module, 
+                       (self->mode == 'r') ? "open" : "create",
+                       self->name);
+       }
+
+       return self;
+}
+
+static int
+gzapi_close(gbfile *self)
+{
+       return gzclose(self->handle.gz);
+}
+
+static int
+gzapi_seek(gbfile *self, gbint32 offset, int whence)
+{
+       int result;
+
+       assert(whence != SEEK_END);
+
+       if ((whence == SEEK_CUR) && (self->back != -1)) offset--;
+       result = gzseek(self->handle.gz, offset, whence);
+       self->back = -1;
+
+       if (result < 0) {
+               if (self->is_pipe)
+                       fatal("%s: This format cannot be used in piped commands!\n", self->module);
+               fatal("%s: online compression not yet supported for this format!", self->module);
+       }
+       return 0;
+}
+
+static gbsize_t
+gzapi_read(void *buf, const gbsize_t size, const gbsize_t members, gbfile *self)
+{
+       int result = 0;
+       char *target = buf;
+       int count = size * members;
+               
+       if (self->back != -1) {
+               *target++ = self->back;
+               count--;
+               result++;
+               self->back = -1;
+       }
+       result += gzread(self->handle.gz, target, count);
+               
+       /* Check for an incomplete READ */
+       if ((members == 1) && (size > 1) && (result > 0) && (result < (int)size))
+               fatal("%s: Unexpected end of file (EOF)!\n", self->module);
+
+       result /= size;
+
+       if ((result < 0) || ((gbsize_t)result < members)) {
+               int errnum;
+               const char *errtxt;
+                       
+               errtxt = gzerror(self->handle.gz, &errnum);
+                       
+               /* Workaround for zlib bug: buffer error on empty files */
+               if ((errnum == Z_BUF_ERROR) && (gztell(self->handle.gz) == 0)) {
+                       return (gbsize_t) 0;
+               }
+               if ((errnum != Z_STREAM_END) && (errnum != 0))
+                       fatal("%s: zlib returned error %d ('%s')!\n",
+                               self->module, errnum, errtxt);
+       }
+       return (gbsize_t) result;
+}
+
+static gbsize_t
+gzapi_write(const void *buf, const gbsize_t size, const gbsize_t members, gbfile *self)
+{
+       return gzwrite(self->handle.gz, buf, size * members) / size;
+}
+
+static int
+gzapi_flush(gbfile *self)
+{
+       return gzflush(self->handle.gz, Z_SYNC_FLUSH);
+}
+
+static gbsize_t
+gzapi_tell(gbfile *self)
+{
+       gbsize_t result;
+
+       result = gztell(self->handle.gz);
+       if (self->back != -1) result--;
+
+       return result;
+}
+
+static int
+gzapi_eof(gbfile *self)
+{
+       int res = 0;
+               
+       if (self->back != -1) return res;
+
+       res  = gzeof(self->handle.gz);
+       if (!res) {
+               unsigned char test;
+               int len = gzread(self->handle.gz, &test, 1);
+               if (len == 1) {
+                       /* No EOF, put the single byte back into stream */
+                       self->back = test;
+               }
+               else {
+                       /* we are at the end of the file */
+                       if (global_opts.debug_level > 0) {
+                               /* now gzeof() should return 1 */
+                               is_fatal(!gzeof(self->handle.gz), "zlib gzeof error!\n");
+                       }
+                       res = 1;
+               }
+       }
+       return res;
+}
+
+static int
+gzapi_ungetc(const int c, gbfile *self)
+{
+       if (self->back == -1)
+               self->back = c;
+       else
+               fatal(MYNAME ": Cannot store more than one byte back!\n");
+       return c;
+}
+
+static void
+gzapi_clearerr(gbfile *self)
+{
+       gzclearerr(self->handle.gz);
+}
+
+static int
+gzapi_error(gbfile *self)
+{
+       int errnum;
+
+       (void)gzerror(self->handle.gz, &errnum);
+
+       return errnum;
+}
+#endif // #if !ZLIB_INHIBITED
+
+
+/*******************************************************************************/
+/* %%%                         Standard C file api                         %%% */
+/*******************************************************************************/
+
+static gbfile *
+stdapi_open(gbfile *self, const char *mode)
+{
+       self->handle.std = xfopen(self->name, mode, self->module);
+       return self;
+}
+
+static int
+stdapi_close(gbfile *self)
+{
+       return fclose(self->handle.std);
+}
+
+static int
+stdapi_seek(gbfile *self, gbint32 offset, int whence)
+{
+       int result;
+       gbsize_t pos = 0;
+               
+       if (whence != SEEK_SET) pos = ftell(self->handle.std);
+
+       result = fseek(self->handle.std, offset, whence);
+       if (result != 0) {
+               switch (whence) {
+               case SEEK_CUR:
+               case SEEK_END: pos = pos + offset; break;
+               case SEEK_SET: pos = offset; break;
+               default:
+                       fatal("%s: Unknown seek operation (%d) for file %s!\n",
+                               self->module, whence, self->name);
+               }
+               fatal("%s: Unable to set file (%s) to position (%llu)!\n",
+                       self->module, self->name, (long long unsigned) pos);
+       }
+       return 0;
+}
+
+static gbsize_t
+stdapi_read(void *buf, const gbsize_t size, const gbsize_t members, gbfile *self)
+{
+       int errno;
+       gbsize_t result = fread(buf, size, members, self->handle.std);
+               
+       if ((result < members) && (errno = ferror(self->handle.std))) {
+               fatal("%s: Error %d occured during read of file '%s'!\n",
+                       self->module, errno, self->name);
+       }
+       return result;
+}
+
+static gbsize_t
+stdapi_write(const void *buf, const gbsize_t size, const gbsize_t members, gbfile *self)
+{
+       return fwrite(buf, size, members, self->handle.std);
+}
+
+static int
+stdapi_flush(gbfile *self)
+{
+       return fflush(self->handle.std);
+}
+
+static gbsize_t
+stdapi_tell(gbfile *self)
+{
+       return ftell(self->handle.std);
+}
+
+static int
+stdapi_eof(gbfile *self)
+{
+       return feof(self->handle.std);
+}
+
+static int
+stdapi_ungetc(const int c, gbfile *self)
+{
+       return ungetc(c, self->handle.std);
+}
+
+static void
+stdapi_clearerr(gbfile *self)
+{
+       clearerr(self->handle.std);
+}
+
+static int
+stdapi_error(gbfile *self)
+{
+       return ferror(self->handle.std);
+}
+
+
+/*******************************************************************************/
+/* %%%                     Memory stream (memapi)                          %%% */
+/*******************************************************************************/
+
+static gbfile *
+memapi_open(gbfile *self, const char *mode)
+{
+       self->mempos = 0;
+       self->memsz = 0;
+       self->handle.mem = NULL;
+
+       return self;
+}
+
+static int
+memapi_close(gbfile *self)
+{
+       xfree(self->handle.mem);
+
+       return 0;
+}
+
+static int
+memapi_seek(gbfile *self, gbint32 offset, int whence)
+{
+       long long pos = (int)self->mempos;
+       
+       switch (whence) {
+               case SEEK_CUR:
+               case SEEK_END: pos = pos + offset; break;
+               case SEEK_SET: pos = offset; break;
+       }
+
+       if ((pos < 0) || (pos > self->memlen)) return -1;
+       
+       self->mempos = pos;
+       return 0;
+}
+
+static gbsize_t
+memapi_read(void *buf, const gbsize_t size, const gbsize_t members, gbfile *self)
+{
+       gbsize_t count;
+       gbsize_t result = (self->memlen - self->mempos) / size;
+
+       if (result > members) result = members;
+       count = result * size;
+       if (count) {
+               memcpy(buf, self->handle.mem + self->mempos, count);
+               self->mempos += count;
+       }
+
+       return result;
+}
+
+static gbsize_t
+memapi_write(const void *buf, const gbsize_t size, const gbsize_t members, gbfile *self)
+{
+       gbsize_t count;
+       
+       if ((size == 0) && (members == 0)) {    /* truncate stream */
+               self->memlen = self->mempos;
+               return 0;
+       }
+       
+       count = size * members;
+       
+       if (self->mempos + count > self->memsz) {
+               self->memsz = ((self->mempos + count + 4095) / 4096) * 4096;
+               self->handle.mem = xrealloc(self->handle.mem, self->memsz);
+       }
+       memcpy(self->handle.mem + self->mempos, buf, count);
+       self->mempos += count;
+       if (self->mempos > self->memlen) self->memlen = self->mempos;
+
+       return members;
+}
+
+static int
+memapi_flush(gbfile *self)
+{
+       return 0;
+}
+
+static gbsize_t
+memapi_tell(gbfile *self)
+{
+       return self->mempos;
+}
+
+static int
+memapi_eof(gbfile *self)
+{
+       return (self->mempos == self->memlen);
+}
+
+static int
+memapi_ungetc(const int c, gbfile *self)
+{
+       if (self->mempos == 0) return EOF;
+       else {
+               self->mempos--;
+               self->handle.mem[self->mempos] = (unsigned char) c;
+               return c;
+       }
+}
+
+static void
+memapi_clearerr(gbfile *self)
+{
+       return;
+}
+
+static int 
+memapi_error(gbfile *self)
+{
+       return 0;
+}
+
+       
 /* GPSBabel 'file' standard calls */
 
 /*
@@ -65,12 +470,11 @@ gbfopen(const char *filename, const char *mode, const char *module)
                
        file = xcalloc(1, sizeof(*file));
        
-       file->name = xstrdup(filename);
        file->module = xstrdup(module);
-       file->line = xstrdup("");
        file->mode = 'r'; // default
        file->binary = (strchr(mode, 'b') != NULL);
        file->back = -1;
+       file->memapi = (filename == NULL);
        
        for (m = mode; *m; m++) {
                switch(tolower(*m)) {
@@ -85,55 +489,74 @@ gbfopen(const char *filename, const char *mode, const char *module)
                                break;
                }
        }
+
+       if (file->memapi) {
+               file->gzapi = 0;
+               file->name = xstrdup("(Memory stream)");
+
+               file->fileclearerr = memapi_clearerr;
+               file->fileclose = memapi_close;
+               file->fileeof = memapi_eof;
+               file->fileerror = memapi_error;
+               file->fileflush = memapi_flush;
+               file->fileopen = memapi_open;
+               file->fileread = memapi_read;
+               file->fileseek = memapi_seek;
+               file->filetell = memapi_tell;
+               file->fileungetc = memapi_ungetc;
+               file->filewrite = memapi_write;
+       }
+       else {
+               file->name = xstrdup(filename);
+               file->is_pipe = (strcmp(filename, "-") == 0);
        
-       /* Do we have a '.gz' extension in the filename ? */
-       len = strlen(file->name);
-       if ((len > 3) && (case_ignore_strcmp(&file->name[len-3], ".gz") == 0)) {
+               /* Do we have a '.gz' extension in the filename ? */
+               len = strlen(file->name);
+               if ((len > 3) && (case_ignore_strcmp(&file->name[len-3], ".gz") == 0)) {
 #if !ZLIB_INHIBITED
-               /* force gzipped files on output */
-               file->gzapi = 1;
+                       /* force gzipped files on output */
+                       file->gzapi = 1;
 #else
-               fatal(NO_ZLIB);
+                       fatal(NO_ZLIB);
 #endif
-       }
-       
-       if (file->gzapi) {
-#if !ZLIB_INHIBITED
-               char openmode[32];
+               }
 
-               /* under non-posix systems files MUST be opened in binary mode */
-               
-               strcpy(openmode, mode);
-               if (strchr(mode, 'b') == NULL)
-                       strncat(openmode, "b", sizeof(openmode));
+               if (file->gzapi) {
+#if !ZLIB_INHIBITED
                
-               if (strcmp(filename, "-") == 0) {
-                       FILE *fd;
-                       if (file->mode == 'r')
-                               fd = stdin;
-                       else
-                               fd = stdout;
-                       SET_BINARY_MODE(fd);
-                       file->handle.gz = gzdopen(fileno(fd), openmode);
-               }
-               else
-                       file->handle.gz = gzopen(filename, openmode);
-                       
-               if (file->handle.gz == NULL) {
-                       fatal("%s: Cannot %s file '%s'!\n", 
-                               module, 
-                               (file->mode == 'r') ? "open" : "create",
-                               filename);
-               }
-               file->gzapi = 1;
+                       file->fileclearerr = gzapi_clearerr;
+                       file->fileclose = gzapi_close;
+                       file->fileeof = gzapi_eof;
+                       file->fileerror = gzapi_error;
+                       file->fileflush = gzapi_flush;
+                       file->fileopen = gzapi_open;
+                       file->fileread = gzapi_read;
+                       file->fileseek = gzapi_seek;
+                       file->filetell = gzapi_tell;
+                       file->fileungetc = gzapi_ungetc;
+                       file->filewrite = gzapi_write;
 #else
-               /* This is the only runtime test we make */
-               fatal("%s: Zlib was not included in this build.\n", file->module);
+                       /* This is the only runtime test we make */
+                       fatal("%s: Zlib was not included in this build.\n", file->module);
 #endif
+               }
+               else {
+                       file->fileclearerr = stdapi_clearerr;
+                       file->fileclose = stdapi_close;
+                       file->fileeof = stdapi_eof;
+                       file->fileerror = stdapi_error;
+                       file->fileflush = stdapi_flush;
+                       file->fileopen = stdapi_open;
+                       file->fileread = stdapi_read;
+                       file->fileseek = stdapi_seek;
+                       file->filetell = stdapi_tell;
+                       file->fileungetc = stdapi_ungetc;
+                       file->filewrite = stdapi_write;
+               }
        }
-       else {
-               file->handle.std = xfopen(filename, mode, module);
-       }
+
+       file->fileopen(file, mode);
+
 #ifdef DEBUG_MEM
        file->buffsz = 1;
 #else
@@ -167,20 +590,11 @@ void
 gbfclose(gbfile *file)
 {
        if (!file) return;
+       
+       file->fileclose(file);
 
-       if (file->gzapi) {
-#if !ZLIB_INHIBITED
-               gzclose(file->handle.gz);
-#else
-               fatal(NO_ZLIB);
-#endif
-       }
-       else {
-               fclose(file->handle.std);
-       }
        xfree(file->name);
        xfree(file->module);
-       xfree(file->line);
        xfree(file->buff);
        xfree(file);
 }
@@ -240,57 +654,7 @@ gbsize_t
 gbfread(void *buf, const gbsize_t size, const gbsize_t members, gbfile *file)
 {
        if ((size == 0) || (members == 0)) return 0;
-       
-       if (file->gzapi) {
-#if !ZLIB_INHIBITED
-               int result = 0;
-               char *target = buf;
-               int count = size * members;
-               
-               if (file->back != -1) {
-                       *target++ = file->back;
-                       count--;
-                       result++;
-                       file->back = -1;
-               }
-               result += gzread(file->handle.gz, target, count);
-               
-               /* Check for an incomplete READ */
-               if ((members == 1) && (size > 1) && (result > 0) && (result < (int)size))
-                       fatal("%s: Unexpected end of file (EOF)!\n", file->module);
-
-               result /= size;
-
-               if ((result < 0) || ((gbsize_t)result < members)) {
-                       int errnum;
-                       const char *errtxt;
-                       
-                       errtxt = gzerror(file->handle.gz, &errnum);
-                       
-                       /* Workaround for zlib bug: buffer error on empty files */
-                       if ((errnum == Z_BUF_ERROR) && (gztell(file->handle.gz) == 0)) {
-                               return (gbsize_t) 0;
-                       }
-                       if ((errnum != Z_STREAM_END) && (errnum != 0))
-                               fatal("%s: zlib returned error %d ('%s')!\n",
-                                       file->module, errnum, errtxt);
-               }
-               return (gbsize_t) result;
-#else
-               fatal(NO_ZLIB);
-               return -1;
-#endif
-       }
-       else {
-               int errno;
-               gbsize_t result = fread(buf, size, members, file->handle.std);
-               
-               if ((result < members) && (errno = ferror(file->handle.std))) {
-                       fatal("%s: Error %d occured during read of file '%s'!\n",
-                               file->module, errno, file->name);
-               }
-               return result;
-       }
+       return file->fileread(buf, size, members, file);
 }
 
 /*
@@ -383,25 +747,13 @@ gbfwrite(const void *buf, const gbsize_t size, const gbsize_t members, gbfile *f
 {
        int result;
        
-       if ((size == 0) || (members == 0)) return 0;
-
-       if (file->gzapi) {
-#if !ZLIB_INHIBITED
-               result = gzwrite(file->handle.gz, buf, size * members) / size;
-#else
-               fatal(NO_ZLIB);
-               return -1;
-#endif
-       }
-       else {
-               result = fwrite(buf, size, members, file->handle.std);
-       }
-
+       result = file->filewrite(buf, size, members, file);
        if (result != members) {
-               fatal("%s: Could not write %lld bytes to %s!\n", 
+               fatal("%s: Could not write %lld bytes to %s (result %d)!\n", 
                        file->module,
                        (long long int) (members - result) * size,
-                       file->name);
+                       file->name,
+                       result);
        }
                
        return result;
@@ -414,17 +766,7 @@ gbfwrite(const void *buf, const gbsize_t size, const gbsize_t members, gbfile *f
 int
 gbfflush(gbfile *file)
 {
-       if (file->gzapi) {
-#if !ZLIB_INHIBITED
-               return gzflush(file->handle.gz, Z_SYNC_FLUSH);
-#else
-               fatal(NO_ZLIB);
-               return -1;
-#endif
-       }
-       else {
-               return fflush(file->handle.std);
-       }
+       return file->fileflush(file);
 }
 
 /*
@@ -434,16 +776,7 @@ gbfflush(gbfile *file)
 void
 gbfclearerr(gbfile *file)
 {
-       if (file->gzapi) {
-#if !ZLIB_INHIBITED
-               gzclearerr(file->handle.gz);
-#else
-               fatal(NO_ZLIB);
-#endif
-       }
-       else {
-               clearerr(file->handle.std);
-       }
+       file->fileclearerr(file);
 }
 
 /*
@@ -453,20 +786,7 @@ gbfclearerr(gbfile *file)
 int
 gbferror(gbfile *file)
 {
-       int errnum;
-       
-       if (file->gzapi) {
-#if !ZLIB_INHIBITED
-               (void)gzerror(file->handle.gz, &errnum);
-#else
-               fatal(NO_ZLIB);
-               return -1;
-#endif
-       }
-       else {
-               errnum = ferror(file->handle.std);
-       }
-       return errnum;
+       return file->fileerror(file);
 }
 
 /*
@@ -487,46 +807,7 @@ gbfrewind(gbfile *file)
 int
 gbfseek(gbfile *file, gbint32 offset, int whence)
 {
-       int result;
-
-       if (file->gzapi) {
-               
-               assert(whence != SEEK_END);
-
-#if !ZLIB_INHIBITED
-               if ((whence == SEEK_CUR) && (file->back != -1)) offset--;
-               result = gzseek(file->handle.gz, offset, whence);
-               file->back = -1;
-#else
-               result = 1;
-#endif
-               if (result < 0) {
-                       if (strcmp(file->name, "-") == 0)
-                               fatal("%s: This format cannot be used in piped commands!\n", file->module);
-                       fatal("%s: online compression not yet supported for this format!", file->module);
-               }
-               return 0;
-       }
-       else {
-               gbsize_t pos = 0;
-               
-               if (whence != SEEK_SET) pos = ftell(file->handle.std);
-
-               result = fseek(file->handle.std, offset, whence);
-               if (result != 0) {
-                       switch (whence) {
-                       case SEEK_CUR:
-                       case SEEK_END: pos = pos + offset; break;
-                       case SEEK_SET: pos = offset; break;
-                       default:
-                               fatal("%s: Unknown seek operation (%d) for file %s!\n",
-                                       file->module, whence, file->name);
-                       }
-                       fatal("%s: Unable to set file (%s) to position (%llu)!\n",
-                               file->module, file->name, (long long unsigned) pos);
-               }
-               return 0;
-       }
+       return file->fileseek(file, offset, whence);
 }
 
 /*
@@ -536,23 +817,7 @@ gbfseek(gbfile *file, gbint32 offset, int whence)
 gbsize_t 
 gbftell(gbfile *file)
 {
-       gbsize_t result;
-       
-       if (file->gzapi) {
-#if !ZLIB_INHIBITED
-               result = gztell(file->handle.gz);
-               if (file->back != -1) {
-//                     file->back = -1;
-                       result--;
-               }
-#else
-               fatal(NO_ZLIB);
-               result = -1;
-#endif
-       }
-       else {
-               result = ftell(file->handle.std);
-       }
+       gbsize_t result = file->filetell(file);
        if ((signed) result == -1)
                fatal("%s: Could not determine position of file '%s'!\n",
                        file->module, file->name);
@@ -566,38 +831,7 @@ gbftell(gbfile *file)
 int 
 gbfeof(gbfile *file)
 {
-       if (file->gzapi) {
-#if !ZLIB_INHIBITED
-               int res;
-               
-               if (file->back != -1) return 0;
-
-               res  = gzeof(file->handle.gz);
-               if (!res) {
-                       unsigned char test;
-                       int len = gzread(file->handle.gz, &test, 1);
-                       if (len == 1) {
-                               /* No EOF, put the single byte back into stream */
-                               file->back = test;
-                       }
-                       else {
-                               /* we are at the end of the file */
-                               if (global_opts.debug_level > 0) {
-                                       /* now gzeof() should return 1 */
-                                       is_fatal(!gzeof(file->handle.gz), "zlib gzeof error!\n");
-                               }
-                               res = 1;
-                       }
-               }
-               return res;
-#else
-               fatal(NO_ZLIB);
-               return 0;
-#endif
-       }
-       else {
-               return feof(file->handle.std);
-       }
+       return file->fileeof(file);
 }
 
 /*
@@ -607,25 +841,7 @@ gbfeof(gbfile *file)
 int
 gbfungetc(const int c, gbfile *file)
 {
-       int res;
-
-       if (file->gzapi) {
-#if !ZLIB_INHIBITED
-               if (file->back == -1) {
-                       file->back = c;
-                       res = c;
-               }
-               else {
-                       fatal(MYNAME ": Cannot store more than one byte back!\n");
-               }
-#else
-               fatal(NO_ZLIB);
-#endif
-       }
-       else {
-               res = ungetc(c, file->handle.std);
-       }
-       return res;
+       return file->fileungetc(c, file);
 }
 
 /* GPSBabel 'file' enhancements */
@@ -754,7 +970,7 @@ static char *
 gbfgetucs2str(gbfile *file)
 {
        int len = 0;
-       char *result = file->line;
+       char *result = file->buff;
        
        for (;;) {
                char buff[8];
@@ -778,9 +994,9 @@ gbfgetucs2str(gbfile *file)
                
                clen = cet_ucs4_to_utf8(buff, sizeof(buff), c);
 
-               if (len+clen >= file->linesz) {
-                       file->linesz += 64;
-                       result = file->line = xrealloc(file->line, file->linesz + 1);
+               if (len+clen >= file->buffsz) {
+                       file->buffsz += 64;
+                       result = file->buff = xrealloc(file->buff, file->buffsz + 1);
                }
                memcpy(&result[len], buff, clen);
                len += clen;
@@ -799,7 +1015,7 @@ char *
 gbfgetstr(gbfile *file)
 {
        int len = 0;
-       char *result = file->line;
+       char *result = file->buff;
        
        if (file->unicode) return gbfgetucs2str(file);
        
@@ -842,9 +1058,9 @@ gbfgetstr(gbfile *file)
                
                file->unicode_checked = 1;
                
-               if (len == file->linesz) {
-                       file->linesz += 64;
-                       result = file->line = xrealloc(file->line, file->linesz + 1);
+               if (len == file->buffsz) {
+                       file->buffsz += 64;
+                       result = file->buff = xrealloc(file->buff, file->buffsz + 1);
                }
                result[len] = (char)c;
                len++;
@@ -950,5 +1166,25 @@ gbfputpstr(const char *s, gbfile *file)
        return (len + 1);
 }
 
+/* Much more higher level functions */
+
+gbsize_t
+gbfcopyfrom(gbfile *file, gbfile *src, gbsize_t count)
+{
+       char buf[1024];
+       gbsize_t copied = 0;
+
+       while (count) {
+               gbsize_t n = gbfread(buf, 1, (count < sizeof(buf)) ? count : sizeof(buf), src);
+               if (n > 0) {
+                       gbfwrite(buf, 1, n, file);
+                       count -= n;
+                       copied += n;
+               }
+               else break;
+       }
+       return copied;
+}
+
 
 /* Thats all, sorry. */
index d13e24a058c806bb14d62c122d9948151409d56e..639aa7bd4b6527966a34db0a26a5991dfe5e740d 100644 (file)
--- a/gbfile.h
+++ b/gbfile.h
@@ -2,7 +2,7 @@
 
     Common GPSBabel file I/O API
 
-    Copyright (C) 2006 Olaf Klein 
+    Copyright (C) 2006,2007,2008 Olaf Klein, o.b.klein@gpsbabel.org
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 #include "defs.h"
 #include "cet.h"
 
+struct gbfile_s;
+typedef struct gbfile_s gbfile;
+
+typedef void (*gbfclearerr_cb) (gbfile *self);
+typedef int (*gbfclose_cb) (gbfile *self);
+typedef int (*gbfeof_cb) (gbfile *self);
+typedef int (*gbferror_cb) (gbfile *self);
+typedef int (*gbfflush_cb) (gbfile *self);
+typedef gbfile* (*gbfopen_cb) (gbfile *self, const char *mode);
+typedef gbsize_t (*gbfread_cb) (void *buf, const gbsize_t size, const gbsize_t members, gbfile *self);
+typedef int (*gbfseek_cb) (gbfile *self, gbint32 offset, int whence);
+typedef gbsize_t (*gbftell_cb) (gbfile *self);
+typedef gbsize_t (*gbfwrite_cb) (const void *buf, const gbsize_t size, const gbsize_t members, gbfile *self);
+typedef int (*gbfungetc_cb) (const int c, gbfile *self);
+
 typedef struct gbfile_s {
 #ifdef DEBUG_MEM
        void   *dummy;  /* ZERO pointer for stdio oop's */
 #endif
        union {
          FILE *std;
+         unsigned char *mem;
 #if !ZLIB_INHIBITED
          gzFile *gz;
 #endif
        } handle;
        char   *name;
        char   *module;
-       char   *line;
-       int    linesz;
        char   *buff;   /* static growing buffer, primary used by gbprintf */
        int    buffsz;
        char   mode;
        int    back;
+       gbsize_t mempos;        /* curr. position in memory */
+       gbsize_t memlen;        /* max. number of written bytes to memory */
+       gbsize_t memsz;         /* curr. size of allocated memory */
        unsigned char big_endian:1;
        unsigned char binary:1;
        unsigned char gzapi:1;
+       unsigned char memapi:1;
        unsigned char unicode:1;
        unsigned char unicode_checked:1;
-} gbfile;
+       unsigned char is_pipe:1;
+       gbfclearerr_cb fileclearerr;
+       gbfclose_cb fileclose;
+       gbfeof_cb fileeof;
+       gbferror_cb fileerror;
+       gbfflush_cb fileflush;
+       gbfopen_cb fileopen;
+       gbfread_cb fileread;
+       gbfseek_cb fileseek;
+       gbftell_cb filetell;
+       gbfungetc_cb fileungetc;
+       gbfwrite_cb filewrite;
+} gbfile_t;
 
 
 gbfile *gbfopen(const char *filename, const char *mode, const char *module);
@@ -100,4 +130,6 @@ int gbfputflt(const float f, gbfile *file); // write a float value
 int gbfputcstr(const char *s, gbfile *file);   // write string including '\0'
 int gbfputpstr(const char *s, gbfile *file);   // write as pascal string
 
+gbsize_t gbfcopyfrom(gbfile *file, gbfile *src, gbsize_t count);
+
 #endif